﻿
namespace UITest.CUIT.HtmlReport
{
    using System;
    using System.Diagnostics;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.IO;
    using System.Reflection;

    using Microsoft.VisualStudio.TestTools.UITesting;

    /// <summary>
    ///     The html report.
    /// </summary>
    public class HtmlReport
    {
        #region Constructors and Destructors

        /// <summary>
        ///     Initializes static members of the <see cref="HtmlReport" /> class.
        /// </summary>
        static HtmlReport()
        {
            ScreenCaptureLevel = CUIT.HtmlReport.ScreenCaptureLevel.CaptureErrorOnly;
            GenerateHtmlReport = false;
            SaveErrorScreenCaptureToFile = false;
            JsName = "Report.HtmlReport.js";
            EmbededCss = "Report.HtmlReport.css";
        }

        #endregion

        #region Public Properties

        /// <summary>
        ///     Gets or sets the embeded CSS in the framework.
        /// </summary>
        public static string EmbededCss { get; set; }

        /// <summary>
        ///     Gets or sets the external CSS in Http Link outside framework.
        /// </summary>
        public static string ExternalCss { get; set; }

        /// <summary>
        ///     Gets or sets the external css list in Http Link outside framework.
        /// </summary>
        public static string[] ExternalCssList { get; set; }

        /// <summary>
        ///     Gets or sets a value indicating whether generate html report.
        /// </summary>
        public static bool GenerateHtmlReport { get; set; }

        /// <summary>
        ///     Gets or sets the Java Script name inside the framework.
        /// </summary>
        public static string JsName { get; set; }

        /// <summary>
        ///     Gets or sets the report full path name.
        /// </summary>
        public static string ReportFullPathName { get; set; }

        /// <summary>
        ///     Gets or sets the report header.
        /// </summary>
        public static string ReportHeader { get; set; }

        /// <summary>
        ///     Gets or sets the report name.
        /// </summary>
        public static string ReportName { get; set; }

        /// <summary>
        ///     Gets or sets the report path.
        /// </summary>
        public static string ReportPath { get; set; }

        /// <summary>
        ///     Gets or sets a value indicating whether save error screen capture.
        /// </summary>
        public static bool SaveErrorScreenCaptureToFile { get; set; }

        /// <summary>
        ///     Gets or sets the screen capture level.
        /// </summary>
        public static int ScreenCaptureLevel { get; set; }


        public static CUIT.CuitContext.CuitContext Context { get; set; }

        #endregion

        #region Properties

        private static string CssName { get; set; }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// The append report error html.
        /// </summary>
        /// <param name="text">
        /// The text.
        /// </param>
        public static void AppendReportErrorHTML(string text)
        {
            if (GenerateHtmlReport)
            {
                var sw = new StreamWriter(@ReportFullPathName, true);

                sw.WriteLine("<tr>");

                // Get Call Method
                var frame = new StackFrame(1);
                string name = frame.GetMethod().Name;
                sw.WriteLine("<td>" + "Method : " + name + "</td>");

                sw.WriteLine("<td class=\"ErrorCell\">" + text + "</td>");

                if (ScreenCaptureLevel > 0)
                {
                    string imageString = CaptureImage(true);
                    sw.WriteLine("<td class=\"screenshot\">" + imageString + "</td>");
                }

                sw.WriteLine("</Tr>");
                sw.Close();
            }
        }

        /// <summary>
        /// The append report html.
        /// </summary>
        /// <param name="text">
        /// The text.
        /// </param>
        /// <param name="stackFrameInt">
        /// The stack frame int.
        /// </param>
        public static void AppendReportHTML(string text, int stackFrameInt = 1)
        {
            if (GenerateHtmlReport)
            {
                var sw = new StreamWriter(@ReportFullPathName, true);

                sw.WriteLine("<tr>");

                // Get Call Method
                var frame = new StackFrame(stackFrameInt);
                string name = frame.GetMethod().Name;
                sw.WriteLine("<td>" + "Method : " + name + "</td>");

                sw.WriteLine("<td>" + text + "</td>");
                if (ScreenCaptureLevel > 1)
                {
                    string imageString = CaptureImage(false);
                    sw.WriteLine("<td class=\"screenshot\">" + imageString + "</td>");
                }

                sw.WriteLine("</tr>");
                sw.Close();
            }

            /*
            if (Context != null && Context.Report!=null && Context.Report.CurrentStep!=null)
            {
                Context.Report.LowStep(new StackFrame(stackFrameInt).GetMethod().Name, text);
            }
             */
        }

        /// <summary>
        ///     The close report html.
        /// </summary>
        public static void CloseReportHTML()
        {
            if (GenerateHtmlReport)
            {
                var sw = new StreamWriter(@ReportFullPathName, true);
                sw.WriteLine("</tbody></Table>");
                sw.WriteLine("</body></html>");
                sw.Close();
            }
        }

        /// <summary>
        ///     The create report html.
        /// </summary>
        public static void CreateReportHTML()
        {
            if (GenerateHtmlReport)
            {
                DefineReportFullPathName();
                DefineReportHeader();
                var sw = new StreamWriter(@ReportFullPathName);

                sw.WriteLine("<!-- saved from url=(0016)http://localhost -->");
                sw.WriteLine("<html><head><center><h1>" + ReportHeader + "</h1></center></head>");

                // CSS
                sw.WriteLine(SwitchCss());

                // JS
                sw.WriteLine(
                    "<script type=\"text/javascript\" src=\"http://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.1.1.min.js\">");
                sw.WriteLine(ReadEmbeddedResoure(JsName));
                sw.WriteLine("</script>");

                sw.WriteLine("<body><p>");
                sw.WriteLine("<Table><tbody>");
                sw.Close();

                Console.WriteLine(ReportFullPathName);
            }
        }

        /// <summary>
        /// The enhanced append html.
        /// </summary>
        /// <param name="text">
        /// The text.
        /// </param>
        /// <param name="htmltag">
        /// The htmltag.
        /// </param>
        /// <param name="htmlClass">
        /// The html class.
        /// </param>
        public static void EnhancedAppendHTML(string text, string htmltag = "DIV", string htmlClass = "")
        {
            if (GenerateHtmlReport)
            {
                var sw = new StreamWriter(@ReportFullPathName, true);
                sw.WriteLine("<{0} class=\"{1}\">{2}</{0}>", htmltag, htmlClass, text);
                sw.Close();
            }
        }

        /// <summary>
        /// The simple append report html.
        /// </summary>
        /// <param name="text">
        /// The text.
        /// </param>
        public static void SimpleAppendReportHTML(string text)
        {
            if (GenerateHtmlReport)
            {
                var sw = new StreamWriter(@ReportFullPathName, true);

                sw.WriteLine("<tr>");
                sw.WriteLine("<td>" + text + "</td>");
                sw.WriteLine("</tr>");
                sw.Close();
            }
        }

        #endregion

        #region Methods

        private static string CaptureImage(bool isError)
        {
            // Capture Desktop
            Image image = UITestControl.Desktop.CaptureImage();

            if (SaveErrorScreenCaptureToFile)
            {
                if (isError)
                {
                    ImageCodecInfo myImageCodecInfo = GetEncoderInfo("image/jpeg");

                    Encoder myEncoder = Encoder.Quality;
                    var myEncoderParameters = new EncoderParameters(1);
                    var myEncoderParameter = new EncoderParameter(myEncoder, 50L);
                    myEncoderParameters.Param[0] = myEncoderParameter;
                    image.Save(
                        ReportPath + "/error_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".jpg", 
                        myImageCodecInfo, 
                        myEncoderParameters);
                }
            }

            byte[] imgBytes = TurnImageToByteArray(image);
            string imgString = Convert.ToBase64String(imgBytes);
            string imageString = string.Format("<img src=\"data:image/png;base64,{0}\"/>", imgString);

            return imageString;
        }

        private static void DefineReportFullPathName()
        {
            if (ReportPath == null)
            {
                ReportPath = @"C:\\temp\";
            }

            if (ReportName == null)
            {
                ReportName = "AST_Report_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".html";
            }

            ReportFullPathName = ReportPath + "/" + ReportName;
        }

        private static void DefineReportHeader()
        {
            if (ReportHeader == null)
            {
                ReportHeader = "Code UI Test Report";
            }
        }

        private static ImageCodecInfo GetEncoderInfo(string mimeType)
        {
            int j;
            ImageCodecInfo[] encoders;
            encoders = ImageCodecInfo.GetImageEncoders();
            for (j = 0; j < encoders.Length; ++j)
            {
                if (encoders[j].MimeType == mimeType)
                {
                    return encoders[j];
                }
            }

            return null;
        }

        private static string ReadEmbeddedResoure(string resourceName)
        {
            Assembly _assembly;
            _assembly = Assembly.GetExecutingAssembly();
            Stream stream = _assembly.GetManifestResourceStream(resourceName);
            var sr = new StreamReader(stream);
            string content = sr.ReadToEnd();
            return content;
        }

        private static string SwitchCss()
        {
            string displayText = null;

            if (ExternalCssList != null)
            {
                for (int i = 0; i < ExternalCssList.Length; i++)
                {
                    CssName = ExternalCssList[i];
                    displayText += "<link rel=\"stylesheet\" href=\"" + CssName + "\" type=\"text/css\">";
                }
            }
            else if (ExternalCss != null)
            {
                CssName = ExternalCss;
                displayText = "<link rel=\"stylesheet\" href=\"" + CssName + "\" type=\"text/css\">";
            }
            else
            {
                CssName = EmbededCss;
                displayText = "<style media=\"screen\" type=\"text/css\">" + ReadEmbeddedResoure(CssName) + "</style>";
            }

            return displayText;
        }

        private static byte[] TurnImageToByteArray(Image img)
        {
            var ms = new MemoryStream();
            img.Save(ms, ImageFormat.Jpeg);
            return ms.ToArray();
        }

        #endregion
    }
}